package com.explorati.design_pattern.creational.singleton;

/**
 * 双重检查延迟加载单例
 * 
 * @author explorati
 *
 */
public class LazyDoubleCheckSingleton {

	//禁止指令重排序优化
	private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

	private LazyDoubleCheckSingleton() {

	}

	public static LazyDoubleCheckSingleton getInstance() {
		/**
		 * 如果为空，则往下执行，锁住整个类，否则直接return
		 */
		//第一次检测
		if (lazyDoubleCheckSingleton == null) {
			//同步
			synchronized (LazyDoubleCheckSingleton.class) {
				if (lazyDoubleCheckSingleton == null) {
					lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
					// 实际执行过程：(单线程安全，多线程有隐患)
					// 1. 分配内存给这个对象
					// 3. 设置 LazyDoubleCheckSingleton 指向分配的内存地址，此时instance!=null,但是对象还没有初始化完成
					// 2. 初始化对象
						// (Java中的规范)intra-thread semantics: 保证重排序不会造成单线程内的程序执行结果
						//对于单线程，2和3改变位置，不会改变执行结果，而且这个重排序可以提高程序的执行性能
						// --------------------3. 设置 LazyDoubleCheckSingleton指向分配的内存地址，此时instance!=null
					
				/**
				 * 多线程时
				 * 线程0                               													 线程1
				 * 1. 分配内存给这个对象
				 * 3. 设置 LazyDoubleCheckSingleton 指向分配的内存地址
				 * 																							 判断Instance是否为null
				 * 																							线程1初次访问对象
				 * 2. 初始化对象
				 * 4.线程0初次访问对象
				 */
					/**
					 * 解决办法 1：防止重排序  使用volatile关键字 修饰lazyDoubleCheckSingleton
					 * 				 2：不让线程1看到重排序
					 */
					//volatile：保证线程的可见性，所有线程都能看到最新的内存状态
				}
			}
		}
		return lazyDoubleCheckSingleton;
	}
}
